<script>
import { PortalTarget } from 'portal-vue';
import { GlCollapsibleListbox } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __ } from '~/locale';
import { scrollToElement, contentTop } from '~/lib/utils/common_utils';
import VulnerabilityCounts from './vulnerability_counts.vue';
import VulnerabilityListGraphql from './vulnerability_list_graphql.vue';
import VulnerabilityFilters from './vulnerability_filters.vue';
import { FILTERS } from './constants';

export default {
  components: {
    VulnerabilityCounts,
    VulnerabilityListGraphql,
    VulnerabilityFilters,
    PortalTarget,
    GlCollapsibleListbox,
  },
  mixins: [glFeatureFlagMixin()],
  inject: {
    isProjectVulnerabilityReport: {
      default: false,
    },
  },
  props: {
    filterDropdowns: {
      type: Array,
      required: true,
    },
    fields: {
      type: Array,
      required: true,
    },
    filterFn: {
      type: Function,
      required: false,
      default: (filters) => filters,
    },
    // Whether this report is visible on the page or not. Intended to be used with tabs so that if
    // the tab that the report is in is not active, the vulnerabilities aren't fetched.
    isVisible: {
      type: Boolean,
      required: false,
      default: true,
    },
    showCounts: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
  data() {
    return {
      selectedGroup: '',
      graphqlFilters: undefined,
    };
  },
  computed: {
    shouldShowProjectNamespace() {
      return this.filterDropdowns.includes(FILTERS.PROJECT);
    },
    shouldShowGroupByButton() {
      return this.glFeatures.vulnerabilityReportGrouping && this.isProjectVulnerabilityReport;
    },
  },
  methods: {
    updateGraphqlFilters(graphqlFilters) {
      this.graphqlFilters = this.filterFn(graphqlFilters);
    },
    emitCountsChanged(counts) {
      this.$emit('counts-changed', counts);
    },
    scrollToTopOfList() {
      const { vulnerabilityListTop } = this.$refs;
      // Only scroll to the top of the vulnerability list if it's above and outside the main content
      // area (the space below the static page header).
      if (vulnerabilityListTop.getBoundingClientRect().top < contentTop()) {
        scrollToElement(vulnerabilityListTop);
      }
    },
  },
  portalName: 'vulnerability-report-sticky',
  groupByOptions: [
    { value: '', text: __('None') },
    { value: 'status', text: __('Status') },
    { value: 'severity', text: __('Severity') },
  ],
};
</script>

<template>
  <div>
    <vulnerability-counts
      v-if="showCounts"
      class="gl-mb-7"
      :filters="graphqlFilters"
      @counts-changed="emitCountsChanged"
    />

    <div ref="vulnerabilityListTop" data-testid="vulnerability-list-top"></div>

    <div class="security-dashboard-filters gl-bg-white">
      <vulnerability-filters :filters="filterDropdowns" @filters-changed="updateGraphqlFilters" />
      <div
        v-if="shouldShowGroupByButton"
        class="gl-display-flex gl-align-items-center gl-p-5 gl-bg-gray-10 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
      >
        <label for="group-by" class="gl-m-0">{{ __('Group by:') }}</label>
        <gl-collapsible-listbox
          id="group-by"
          v-model="selectedGroup"
          category="tertiary"
          class="gl-ml-2"
          :items="$options.groupByOptions"
        />
      </div>
      <portal-target v-if="isVisible" :name="$options.portalName" />
    </div>

    <vulnerability-list-graphql
      v-if="isVisible"
      :class="{ 'has-group-by': shouldShowGroupByButton }"
      :fields="fields"
      :filters="graphqlFilters"
      :show-project-namespace="shouldShowProjectNamespace"
      :portal-name="$options.portalName"
      @vulnerability-clicked="$emit('vulnerability-clicked', $event)"
      @query-variables-changed="scrollToTopOfList"
    />
  </div>
</template>
